#ifndef __ACPI_H__
#define __ACPI_H__

#include <kernel/global.h>
#include <std/stdint.h>

#define SIGNATURE_16(A, B)        ((A) | (B << 8))
#define SIGNATURE_32(A, B, C, D)  (SIGNATURE_16 (A, B) \
                                  | (SIGNATURE_16 (C, D) << 16))
#define SIGNATURE_64(A, B, C, D, E, F, G, H) \
    (SIGNATURE_32 (A, B, C, D) | ((uint64_t) (SIGNATURE_32 (E, F, G, H)) << 32))


// #define SIGNATURE32(A,B,C,D) ( D << 24 | C << 16 | B << 8 | A)

#define MADT_SIGNATURE SIGNATURE_32('A','P','I','C') //"APIC"
#define BGRT_SIGNATURE SIGNATURE_32('B','G','R','T') //"BGRT"
#define BERT_SIGNATURE SIGNATURE_32('B','E','R','T') //"BERT"
#define CPEP_SIGNATURE SIGNATURE_32('C','P','E','P') //"CPEP"
#define DSDT_SIGNATURE SIGNATURE_32('D','S','D','T') //"DSDT"
#define ECDT_SIGNATURE SIGNATURE_32('E','C','D','T') //"ECDT"
#define EINJ_SIGNATURE SIGNATURE_32('E','I','N','J') //"EINJ"
#define ERST_SIGNATURE SIGNATURE_32('E','R','S','T') //"ERST"
#define FADT_SIGNATURE SIGNATURE_32('F','A','C','P') //"FACP"
#define FACS_SIGNATURE SIGNATURE_32('F','A','C','S') //"FACS"
#define HEST_SIGNATURE SIGNATURE_32('H','E','S','T') //"HEST"
#define MSCT_SIGNATURE SIGNATURE_32('M','S','C','T') //"MSCT"
#define MPST_SIGNATURE SIGNATURE_32('M','P','S','T') //"MPST"

#define PMTT_SIGNATURE SIGNATURE_32('P','M','T','T') //"PMTT"
#define PSDT_SIGNATURE SIGNATURE_32('P','S','D','T') //"PSDT"
#define RASF_SIGNATURE SIGNATURE_32('R','A','S','F') //"RASF"

#define SBST_SIGNATURE SIGNATURE_32('S','B','S','T') //"SBST"
#define SLIT_SIGNATURE SIGNATURE_32('S','L','I','T') //"SLIT"
#define SRAT_SIGNATURE SIGNATURE_32('S','R','A','T') //"SRAT"
#define SSDT_SIGNATURE SIGNATURE_32('S','S','D','T') //"SSDT"

#pragma pack(1)
typedef struct
{
    uint32_t Signature;
    uint32_t Length;
    uint8_t  Revision;
    uint8_t  Checksum;
    uint8_t  OemId[6];
    uint64_t OemTableId;
    uint32_t OemRevision;
    uint32_t CreatorId;
    uint32_t CreatorRevision;
} ACPI_DESCRIPTION_HEADER_t;

typedef struct
{
    ACPI_DESCRIPTION_HEADER_t Header;
    uint32_t                  Entry;
} RSDT_TABLE_t;

typedef struct
{
    ACPI_DESCRIPTION_HEADER_t Header;
    uint64_t                  Entry;
} XSDT_TABLE_t;

typedef struct
{
  uint8_t AddressSpace;
  uint8_t BitWidth;
  uint8_t BitOffset;
  uint8_t AccessSize;
  uint64_t Address;
} GenericAddressStructure_t;

typedef struct
{
    ACPI_DESCRIPTION_HEADER_t Header;
    uint32_t FirmwareCtrl;
    uint32_t Dsdt;

    // field used in ACPI 1.0; no longer in use, for compatibility only
    uint8_t  Reserved;

    uint8_t  PreferredPowerManagementProfile;
    uint16_t SCI_Interrupt;
    uint32_t SMI_CommandPort;
    uint8_t  AcpiEnable;
    uint8_t  AcpiDisable;
    uint8_t  S4BIOS_REQ;
    uint8_t  PSTATE_Control;
    uint32_t PM1aEventBlock;
    uint32_t PM1bEventBlock;
    uint32_t PM1aControlBlock;
    uint32_t PM1bControlBlock;
    uint32_t PM2ControlBlock;
    uint32_t PMTimerBlock;
    uint32_t GPE0Block;
    uint32_t GPE1Block;
    uint8_t  PM1EventLength;
    uint8_t  PM1ControlLength;
    uint8_t  PM2ControlLength;
    uint8_t  PMTimerLength;
    uint8_t  GPE0Length;
    uint8_t  GPE1Length;
    uint8_t  GPE1Base;
    uint8_t  CStateControl;
    uint16_t WorstC2Latency;
    uint16_t WorstC3Latency;
    uint16_t FlushSize;
    uint16_t FlushStride;
    uint8_t  DutyOffset;
    uint8_t  DutyWidth;
    uint8_t  DayAlarm;
    uint8_t  MonthAlarm;
    uint8_t  Century;

    // reserved in ACPI 1.0; used since ACPI 2.0+
    uint16_t BootArchitectureFlags;

    uint8_t  Reserved2;
    uint32_t Flags;

    // 12 byte structure; see below for details
    GenericAddressStructure_t ResetReg;

    uint8_t  ResetValue;
    uint8_t  Reserved3[3];

    // 64bit pointers - Available on ACPI 2.0+
    uint64_t                X_FirmwareControl;
    uint64_t                X_Dsdt;

    GenericAddressStructure_t X_PM1aEventBlock;
    GenericAddressStructure_t X_PM1bEventBlock;
    GenericAddressStructure_t X_PM1aControlBlock;
    GenericAddressStructure_t X_PM1bControlBlock;
    GenericAddressStructure_t X_PM2ControlBlock;
    GenericAddressStructure_t X_PMTimerBlock;
    GenericAddressStructure_t X_GPE0Block;
    GenericAddressStructure_t X_GPE1Block;
} FADT_t;

#pragma pack()

PUBLIC void* find_rsdp(uint8_t* start,uint8_t* end);
PUBLIC void init_acpi();
PUBLIC void* acpi_get_table(uint32_t signature);

#endif